{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\ProgramData\\Anaconda3\\lib\\site-packages\\h5py\\__init__.py:34: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "from tensorflow.examples.tutorials.mnist import input_data\n",
    "from tensorflow.contrib.tensorboard.plugins import projector"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting C:\\Users\\zdwxx\\Downloads\\Compressed\\MNIST_data\\train-images-idx3-ubyte.gz\n",
      "Extracting C:\\Users\\zdwxx\\Downloads\\Compressed\\MNIST_data\\train-labels-idx1-ubyte.gz\n",
      "Extracting C:\\Users\\zdwxx\\Downloads\\Compressed\\MNIST_data\\t10k-images-idx3-ubyte.gz\n",
      "Extracting C:\\Users\\zdwxx\\Downloads\\Compressed\\MNIST_data\\t10k-labels-idx1-ubyte.gz\n",
      "第 0 个周期 准确率是 0.1543\n",
      "第 550 个周期 准确率是 0.765\n",
      "第 1100 个周期 准确率是 0.7856\n",
      "第 1650 个周期 准确率是 0.7886\n",
      "第 2200 个周期 准确率是 0.8763\n",
      "第 2750 个周期 准确率是 0.8876\n",
      "第 3300 个周期 准确率是 0.9844\n",
      "第 3850 个周期 准确率是 0.9859\n",
      "第 4400 个周期 准确率是 0.9859\n",
      "第 4950 个周期 准确率是 0.9876\n",
      "第 5500 个周期 准确率是 0.9873\n",
      "第 6050 个周期 准确率是 0.987\n",
      "第 6600 个周期 准确率是 0.9883\n",
      "第 7150 个周期 准确率是 0.9895\n",
      "第 7700 个周期 准确率是 0.9888\n",
      "第 8250 个周期 准确率是 0.9887\n",
      "第 8800 个周期 准确率是 0.9898\n",
      "第 9350 个周期 准确率是 0.9882\n",
      "第 9900 个周期 准确率是 0.9907\n",
      "第 10450 个周期 准确率是 0.9906\n",
      "第 11000 个周期 准确率是 0.9905\n"
     ]
    }
   ],
   "source": [
    "# 载入数据集\n",
    "mnist = input_data.read_data_sets(r\"C:\\Users\\zdwxx\\Downloads\\Compressed\\MNIST_data\", one_hot=True)\n",
    "\n",
    "# 运行次数\n",
    "max_steps = 550 * 21\n",
    "\n",
    "# 图片数量\n",
    "image_num = 3000\n",
    "\n",
    "# 定义会话\n",
    "sess = tf.Session()\n",
    "\n",
    "# 文件路径\n",
    "DIR = \"C:/Tensorflow/\"\n",
    "\n",
    "# 载入图片\n",
    "embedding = tf.Variable(tf.stack(mnist.test.images[:image_num]), \n",
    "                        trainable=False, name=\"embedding\")\n",
    "\n",
    "# 定义一个参数概要\n",
    "def varible_summaries(var, name=\"summary\"):\n",
    "    \n",
    "    with tf.name_scope(name):\n",
    "        \n",
    "        mean = tf.reduce_mean(var)\n",
    "        tf.summary.scalar(\"mean\", mean) # 平均值\n",
    "        with tf.name_scope(\"stddev\"):\n",
    "            stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))\n",
    "        tf.summary.scalar(\"stddev\", stddev) # 标准差\n",
    "        tf.summary.scalar(\"max\", tf.reduce_max(var)) #最大值\n",
    "        tf.summary.scalar(\"min\", tf.reduce_min(var)) # 最小值\n",
    "        tf.summary.histogram(\"histogram\", var) # 直方图\n",
    "\n",
    "# 命名空间\n",
    "with tf.name_scope(\"input\"):\n",
    "    # 定义两个placeholder\n",
    "    x = tf.placeholder(tf.float32, [None, 784], name=\"x-input\")\n",
    "    y = tf.placeholder(tf.float32, [None, 10], name=\"y-input\")        \n",
    "\n",
    "# 显示图片\n",
    "with tf.name_scope(\"input_reshape\"):\n",
    "    \n",
    "    image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])\n",
    "    tf.summary.image(\"input\", image_shaped_input, 10)\n",
    "    \n",
    "\n",
    "with tf.name_scope(\"layer\"):\n",
    "        #创建一个简单的神经网络\n",
    "    # 初始化权值函数\n",
    "    def weight_variable(shape):\n",
    "        initial = tf.truncated_normal(shape, stddev=0.1) # 生成一个截断的正态分布\n",
    "        return tf.Variable(initial)\n",
    "\n",
    "    # 初始化偏置值函数\n",
    "    def bias_variable(shape):\n",
    "        initial = tf.constant(0.1, shape=shape)\n",
    "        return tf.Variable(initial)\n",
    "\n",
    "    # 卷积层\n",
    "    def conv2d(x, W):\n",
    "    #   x input tensor of shape:`[filter_height * filter_wid3th * in_channels, output_channels]`.\n",
    "    # `[filter_height, filter_width, in_channels, out_channels]`\n",
    "    # `strides[0] = strides[3] = 1,strides[1]->x方向上的补偿，[2]->y方向上的补偿\n",
    "    # padding: A string from:\"SAME\", \"VAILD\"\n",
    "        return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding=\"SAME\")\n",
    "\n",
    "    # 池化层\n",
    "    def max_pool_2x2(x):\n",
    "    # ksize[1,x,y,1]\n",
    "        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding=\"SAME\")\n",
    "\n",
    "    # 改变x的格式转为4D的向量[batch, in_height, in_widch, in_channels]\n",
    "    x_image = tf.reshape(x, [-1, 28, 28, 1]) # [批次，高，宽，通道]\n",
    "\n",
    "    # 初始化第一个卷积层的权值和偏置值\n",
    "    W_conv1 = weight_variable([5, 5, 1, 32]) # 5*5的采样窗口，32个卷积核从1个平面抽取特征\n",
    "\n",
    "    b_conv1 = bias_variable([32]) # 每一个卷积核的偏置值\n",
    "\n",
    "\n",
    "\n",
    "    # 把x_image的权值进行卷积，加上偏置值，然后应用于relu激活函数\n",
    "\n",
    "    h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)\n",
    "    h_pool1 = max_pool_2x2(h_conv1) # 进行max_pool\n",
    "\n",
    "\n",
    "    # 初始化第二个卷积层的权值和偏置值\n",
    "    W_conv2 = weight_variable([5, 5, 32, 64]) # 5*5的采样窗口，64个卷积核从32个平面抽取特征\n",
    "\n",
    "    b_conv2 = bias_variable([64]) # 每一个卷积核的偏置值\n",
    "\n",
    "\n",
    "    # 把x_image的权值进行卷积，加上偏置值，然后应用于relu激活函数\n",
    "    h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)\n",
    "    h_pool2 = max_pool_2x2(h_conv2) # 进行max_pool\n",
    "\n",
    "\n",
    "    # 28*28的图片第一次卷积后还是28*28，第一次池化后变成了14*14\n",
    "    # 第二次卷积后为14*14，第二次池化后变成了7*7\n",
    "    # 通过上面的操作后得到了64张7*7的平面\n",
    "\n",
    "    # 初始化第一个全连接层的权值\n",
    "    W_fc1 = weight_variable([7*7*64, 1024])\n",
    "\n",
    "    b_fc1 = bias_variable([1024])\n",
    "\n",
    "\n",
    "    # 把池化层2的输出扁平化为1维\n",
    "    h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])\n",
    "\n",
    "    # 求出第一个全连接层的输出\n",
    "    h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)\n",
    "\n",
    "#     # 使用dropout防止过拟合\n",
    "#     h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)\n",
    "\n",
    "\n",
    "    # 初始化第二个全连接层\n",
    "    W_fc2 = weight_variable([1024, 10])\n",
    "\n",
    "    b_fc2 = bias_variable([10])\n",
    "\n",
    "\n",
    "    # 计算输出\n",
    "    prediction = tf.nn.softmax(tf.matmul(h_fc1, W_fc2) + b_fc2)\n",
    "\n",
    "# 二次代价函数\n",
    "\n",
    "# loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))\n",
    "with tf.name_scope(\"loss\"):\n",
    "    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))\n",
    "    tf.summary.scalar(\"loss\", loss)\n",
    "    \n",
    "# Adam\n",
    "with tf.name_scope(\"train\"):\n",
    "    train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)\n",
    "\n",
    "# 初始化变量\n",
    "init = tf.global_variables_initializer()\n",
    "sess.run(init)\n",
    "\n",
    "with tf.name_scope(\"accuracy\"):\n",
    "    # 结果存放在一个布尔型列表中\n",
    "    with tf.name_scope(\"correct_prediction\"):\n",
    "        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1)) #argmax返回1维张量中最大的值所在的位置\n",
    "    # 求准确率\n",
    "    with tf.name_scope(\"accuracy\"):\n",
    "        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))#cast转换类型，True->1.0, False->0.0\n",
    "        tf.summary.scalar(\"accuracy\", accuracy)\n",
    "\n",
    "# 产生 metadata文件        \n",
    "if tf.gfile.Exists(DIR + \"projector/projector/metadata.tsv\"):\n",
    "    tf.gfile.DeleteRecursively(DIR + \"projector/projector/metadata.tsv\")\n",
    "\n",
    "with open(DIR + \"projector/projector/metadata.tsv\", \"w\") as f:\n",
    "    lables = sess.run(tf.argmax(mnist.test.labels[:], 1))\n",
    "    for i in range(image_num):\n",
    "        f.write(str(lables[i]) + \"\\n\")\n",
    "\n",
    "# 合并所有的summary\n",
    "merged = tf.summary.merge_all()\n",
    "\n",
    "\n",
    "projector_writer = tf.summary.FileWriter(DIR + \"projector/projector\", sess.graph)\n",
    "saver = tf.train.Saver()\n",
    "config = projector.ProjectorConfig()\n",
    "embed = config.embeddings.add()\n",
    "embed.tensor_name = embedding.name\n",
    "embed.metadata_path = DIR + \"projector/projector/metadata.tsv\"\n",
    "embed.sprite.image_path = DIR + \"projector/data/mnist_10k_sprite.png\"\n",
    "embed.sprite.single_image_dim.extend([28, 28])\n",
    "projector.visualize_embeddings(projector_writer, config)\n",
    "    \n",
    "\n",
    "for i in range(max_steps):\n",
    "\n",
    "    batch_xs, batch_ys = mnist.train.next_batch(100) #类似于read，一次读取100张图片\n",
    "    run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)\n",
    "    run_metadata = tf.RunMetadata()\n",
    "    sess.run(train_step, feed_dict={x : batch_xs, y : batch_ys})\n",
    "    projector_writer.add_run_metadata(run_metadata, \"step%03d\" % i)\n",
    "\n",
    "    \n",
    "    if i % 550 == 0:\n",
    "        acc = sess.run(accuracy, feed_dict={x:mnist.test.images, y:mnist.test.labels})\n",
    "        summary = sess.run(merged, feed_dict={x:mnist.test.images, y:mnist.test.labels})\n",
    "        projector_writer.add_summary(summary, i)\n",
    "        print(\"第\", i, \"个周期\", \"准确率是\", acc)\n",
    "\n",
    "saver.save(sess, DIR + \"projector/projector/a_model.ckpt\")\n",
    "projector_writer.close()\n",
    "sess.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
